home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Tool Chest / Development Platforms / Macintosh Common Lisp Related / User Contributions / mapforms (code walker).sea / mapforms (code walker) / mapforms.lisp < prev    next >
Encoding:
Text File  |  1992-04-21  |  48.6 KB  |  1,099 lines  |  [TEXT/CCL2]

  1. ;;; -*- Mode:LISP; Package:Language-Tools; Syntax:Common-Lisp -*-
  2. ;;;>>SHARED-MESSAGE
  3. ;;;>
  4. ;;;>******************************************************************************************
  5. ;;;>    This may only be used as permitted under the license agreement under
  6. ;;;>    which it has been distributed, and in no other way.
  7. ;;;>******************************************************************************************
  8. ;;;>
  9. ;;;>
  10. ;;; Written May 1982 by David A. Moon for use by the Common Lisp community
  11. ;;; Revised April 1983
  12.  
  13. ;;; Tools for source code analysis: code-walker
  14.  
  15. ;--- Common Lisp version conversion issues:
  16. ;--- new DECLARE not hacked yet
  17. ;--- Doesn't handle lexically-enclosed functions and macros yet
  18. ;--- use Common Lisp condition system to signal errors, when it has one
  19. ;--- BLOCK has to be processed in a very funny way?  See (RETURN MAPFORMS)
  20. ;--- Certain symbols, e.g. SYMEVAL, aren't CL function names any more
  21. ;--- Uses extended DEFUN syntax for defining functions as properties
  22. ;--- Depends on having LOOP of course
  23.  
  24. ;;; Interface definitions
  25.  
  26. ;; All symbols that are part of the interface are exported from the LT package
  27.  
  28. (EXPORT '(MAPFORMS COPYFORMS MAPFORMS-1 COPYFORMS-1            ;Functions
  29.       CALL BODY TEST EFFECT SMASH PROP ARG-TEMPLATE REPEAT EXPR    ;Template things
  30.       PARALLEL-LET ANONYMOUS-BLOCK ORDER ARBITRARY
  31.       BLOCK QUOTE SYMEVAL SET LET DECLARE GO RETURN-FROM        ;Template things that
  32.       EVAL FUNCTION PROG RETURN COND LOOP                ; are already global
  33.       FORM-NOT-UNDERSTOOD                        ;Condition
  34.       *MAPFORMS-BOUND-VARIABLES* *MAPFORMS-BLOCK-NAMES*        ;Variables
  35.       *MAPFORMS-GO-TAGS* *MAPFORMS-NON-FORM-KINDS*))
  36.  
  37. #+EXPLORER
  38. (DEFMACRO ENV-FUNCTIONS (FOO)
  39.   `(CADR ,FOO))
  40.  
  41. ;; The entry functions to this module are MAPFORMS and COPYFORMS
  42. ;;  which take a funarg, a form, and keywords, and call the funarg on parts of the form.
  43. ;;  MAPFORMS-1 and COPYFORMS-1 may be called from inside the funarg.
  44. ;; The ARG-TEMPLATE declaration is used when defining a special form.
  45. ;; The MAPFORMS property may be used for complex special forms.
  46. ;; Errors detected are of two kinds:
  47. ;;  Problems with the form being mapped over signal FORM-NOT-UNDERSTOOD
  48. ;;    These errors may always be proceeded and will do something reasonable by default.
  49. ;;    This code isn't as careful as it could be about checking for dotted lists in forms.
  50. ;;  Bugs in MAPFORMS itself, or in templates, are signalled with ERROR.
  51.  
  52. ;;; KIND
  53. ;; A piece of Lisp code has a KIND, saying what it is, independent of context.
  54. ;; The following kinds are forms (they get evaluated):
  55. ;;    QUOTE - a constant (whether quoted or self-evaluating or same-evaluating)
  56. ;;        i.e. this form is guaranteed always to evaluate the same no
  57. ;;        matter how many times and in what context you evaluate it
  58. ;;    SYMEVAL - a variable reference
  59. ;;    a list - a function combination of any sort (normal, special, or lambda)
  60. ;;      for special forms, the list is non-empty and its cdr is the arg-template 
  61. ;;        to be matched against the cdr of the form (see next page)
  62. ;;      for regular function combinations, the list is NIL
  63. ;; The following kinds are not forms:
  64. ;;    SET - a variable being setqed
  65. ;;    LET - a variable being bound
  66. ;;    DECLARE - a local declaration
  67. ;;    GO - a prog tag being gone to
  68. ;;    RETURN-FROM - a block name (prog name) being returned from
  69. ;;    ARBITRARY - an arbitrary side-effect not associated with any particular piece
  70. ;;        of Lisp code.  The code passed is just the name of the special form involved.
  71.  
  72. ;;; USAGE
  73. ;; The context of a piece of Lisp code is described by a usage symbol.
  74. ;; These are the usages that the MAPFORMS funarg will see.  The somewhat
  75. ;; similar usages used in arg templates are described on the next page.
  76. ;;
  77. ;; The following usages imply evaluation, and tell something about how the result
  78. ;; of the evaluation is used:
  79. ;;    EVAL - general case
  80. ;;    TEST - all that matters is whether the value is NIL
  81. ;;    EFFECT - the value is not used
  82. ;;    SMASH - the resulting object is modified (e.g. NREVERSE)
  83. ;;    PROP - the result is used as a property name
  84. ;;    FUNCTION - the result is used as a function
  85. ;;  more of these are likely to be added in the future; unrecognized usages should be
  86. ;;  assumed to imply evaluation
  87. ;;--- SMASH and PROP templates have not been put in on the many functions that would
  88. ;;--- need them.  Interlisp seems to find these useful; we could put them in someday.
  89. ;;  The KIND of a form used with one of the above usages will necessarily be
  90. ;;  one of the "form" kinds: QUOTE, SYMEVAL, or a list.
  91. ;;
  92. ;; The following usages do not imply evaluation, hence don't go with forms:
  93. ;;    QUOTE - a subform that is not evaluated
  94. ;;    SET - a variable being setq'ed
  95. ;;    LET - a variable being bound
  96. ;;    SYMEVAL - a variable used as a variable (but not a form)
  97. ;;    CALL - a function (typically inside of #')
  98. ;;    GO - a prog tag being gone to
  99. ;;    RETURN-FROM - a block name being returned from
  100. ;;    DECLARE - a local declaration
  101. ;;    ARBITRARY - some arbitrary side-effect is occurring, not associated
  102. ;;            with a particular form.  The piece of Lisp code
  103. ;;            is the name of the special form involved.
  104. ;; Each of the above non-form usages has a characteristic KIND that goes with
  105. ;; it.  This is the same symbol, except for CALL where the KIND is QUOTE.
  106.  
  107. ;;; ARG-TEMPLATE declaration
  108. ;;
  109. ;; An argument template is a tree which is matched against the cdr of a form.
  110. ;; Leaves of the tree are symbols or lists with special symbols in their car,
  111. ;; and usually match forms to be evaluated (sometimes they match special syntactic
  112. ;; things).  The leaves define where the forms to be evaluated are and also
  113. ;; something about how the arguments are used.  Thus many of the symbols that
  114. ;; may be used as leaves are the same as the USAGE symbols listed above.
  115. ;;
  116. ;; Possible leaves are:
  117. ;;    QUOTE - this expression is not evaluated
  118. ;;    SET - a variable appearing here is setqed
  119. ;;    LET - a variable appearing here is bound (a list is a variable and a value)
  120. ;;    PARALLEL-LET - like ((REPEAT LET)) but the bindings are done in parallel
  121. ;;    SYMEVAL - a variable appearing here is used as a variable (but is not a form)
  122. ;;    CALL - this expression is not evaluated, but if it is a function it is called
  123. ;;    BODY - any number of expressions, all but the last for effect ("progn")
  124. ;;    DECLARE - any number of local declarations and documentation strings may appear here
  125. ;;      (the funarg sees single declarations with a usage of DECLARE)
  126. ;;     PROG - prog tags and forms evaluated for effect (a prog body)
  127. ;;    GO - this expression is not evaluated (it's a prog tag being gone to)
  128. ;;    RETURN-FROM - this expression is not evaluated (it's a block name being returned from)
  129. ;;    BLOCK - this expression is not evaluated (it's a block name being defined)
  130. ;;    EVAL - a form is evaluated
  131. ;;    TEST - a form is evaluated, but all that matters is whether the value is NIL
  132. ;;    EFFECT - a form is evaluated, but its value is not used
  133. ;;     RETURN - a form is evaluated, and its value is also the value of the whole form
  134. ;;    SMASH - a form is evaluated and the resulting object is modified (e.g. NREVERSE)
  135. ;;    PROP - a form is evaluated and the result is used as a property name
  136. ;;    FUNCTION - a form is evaluated and the result is used as a function
  137. ;;    ARBITRARY - does not match any subform; indicates that an arbitrary
  138. ;;        side-effect occurs at this point.  This is an "escape hatch"
  139. ;;        for special forms that don't fit in to the model very well.
  140. ;;   The next three are attributes of the whole form and don't match any subforms
  141. ;;   These must appear at the front of a template
  142. ;;    COND - this form is a conditional; it doesn't necessarily evaluate all its subforms.
  143. ;;    LOOP - this form is an iteration; it may evaluate some subforms no or multiple times.
  144. ;;     ANONYMOUS-BLOCK - indicates an unnamed prog
  145. ;;   The remaining leaves are "complex".
  146. ;;    REPEAT and ORDER match multiple subforms, the others match one.
  147. ;;    (REPEAT template template...) - the sequence of templates is repeated zero
  148. ;;        or more times, to match the length of the form
  149. ;;    (IF predicate true-template false-template) - use predicate to decide
  150. ;;        which template to use.  If predicate is atomic, it is a function
  151. ;;        applied to the matching expression, otherwise it is a form to
  152. ;;        to evaluate with EXPR bound to the matching expression.
  153. ;;    (ORDER (n template) (n template)...) - the next several subforms are matched
  154. ;;        to the templates in order.  But the order of evaluation (and hence
  155. ;;        of mapforms processing) is not left-to-right, but is according
  156. ;;        to increasing numerical order of the numbers "n".
  157. ;;        By special hair, one of the templates may be a REPEAT.
  158. ;;   The following two can really screw things up when the correspondence between
  159. ;;   what is analyzed and the original code matters.  Fortunately they aren't
  160. ;;   used currently.  They come from Interlisp.
  161. ;;    (AND template template...) - all of the templates specified apply
  162. ;;        this causes the matching expression to be analyzed multiple times
  163. ;;    (MACRO expr template) - expr and template are forms to be evaluated,
  164. ;;        with EXPR bound to the matching expression.  Use the results as
  165. ;;        the new matching expression and the new template.
  166. ;;  more of these are likely to be added in the future; unrecognized symbols should be
  167. ;;  assumed to imply evaluation
  168. ;;
  169. ;; Error if the form is longer than the template, but not vice versa (optional args).
  170. ;;
  171. ;; Example declaration for COND:
  172. ;;    (DECLARE (ARG-TEMPLATE COND (REPEAT (TEST . BODY))))
  173. ;; For IF (with multi-else feature):
  174. ;;    (DECLARE (ARG-TEMPLATE COND TEST RETURN . BODY))
  175.  
  176. (DEFPROP ARG-TEMPLATE T COMPILER:DEBUG-INFO)
  177.  
  178. ;;; The following variables are likely to be used by the user.
  179.  
  180. ;;; This variable contains a list of the variables bound around the current form
  181. ;;; or the symbol NO-ENV if we were not asked to keep track of that
  182. (DEFVAR *MAPFORMS-BOUND-VARIABLES*)
  183.  
  184. ;;; If bound variables maintained, this list of block names extant is maintained
  185. (DEFVAR *MAPFORMS-BLOCK-NAMES*)
  186.  
  187. ;;; If bound variables maintained, this list of go tags extant is maintained
  188. (DEFVAR *MAPFORMS-GO-TAGS*)
  189.  
  190. ;;; The KIND symbols that correspond to non-form Lisp code fragments
  191. (DEFPARAMETER *MAPFORMS-NON-FORM-KINDS* '(SET LET DECLARE GO RETURN-FROM ARBITRARY))
  192.  
  193. ;;; Also LOCAL-DECLARATIONS will be bound appropriately for any local
  194. ;;; DECLAREs that are encountered.
  195.  
  196. ;;; The user may call back into MAPFORMS-1 or COPYFORMS-1 when bypassing
  197. ;;; normal processing.  Don't forget to return a second value of T.
  198.  
  199. ;;; Mapforms/Copyforms top level
  200.  
  201. ;;; This variable is an a-list of arg-templates, for those which for whatever
  202. ;;; reason are not in the function's debugging info.
  203. (DEFVAR *ARG-TEMPLATE-ALIST* NIL)
  204.  
  205. ;;; The following variables are bound at entry to MAPFORMS or COPYFORMS
  206.  
  207. ;;; This variable contains an a-list of the block names defined around the current form.
  208. ;;; The cdr of each entry is the USAGE of that block.
  209. ;;; This list is a stack list, and hence must not be squirelled away
  210. (DEFVAR *MAPFORMS-BLOCK-ALIST*)
  211.  
  212. (DEFVAR *MAPFORMS-FUNCTION*)            ;Function being mapped
  213. (DEFVAR *MAPFORMS-STATE*)            ;Holds state returned by user function
  214. (DEFVAR *MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*);An interpreter environment
  215.                         ;for tracking MACROLET's and FLET's 
  216. (DEFVAR *COPYFORMS-FLAG*)            ;T if copying/transforming subforms
  217. (DEFVAR *MAPFORMS-APPLY-FUNCTION*)        ;Post-processing function
  218. (DEFVAR *MAPFORMS-ITERATION-HOOK*)        ;:ITERATION-HOOK function
  219. (DEFVAR *MAPFORMS-EXPAND-SUBSTS*)        ;:EXPAND-SUBSTS flag
  220. (DEFVAR *MAPFORMS-PARALLEL-BINDS*)        ;Side-effect from MAPFORMS-BIND
  221. (DEFVAR *COPYFORMS-EXPAND-ALL-MACROS* NIL)    ;T to copy macro expansions
  222.         ;(needs a top-level value, but it doesn't matter what it is!)
  223.  
  224.  
  225. (DEFUN MAPFORMS (*MAPFORMS-FUNCTION* FORM
  226.          &KEY (INITIAL-STATE NIL)
  227.               (BOUND-VARIABLES 'NO-ENV)
  228.               (USAGE 'EVAL)
  229.               (APPLY-FUNCTION NIL)
  230.               (ITERATION-HOOK NIL)
  231.               (EXPAND-SUBSTS NIL)
  232.          &AUX (*COPYFORMS-FLAG* NIL)
  233.               (*MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT* NIL)
  234.               (*MAPFORMS-BOUND-VARIABLES* BOUND-VARIABLES)
  235.               (*MAPFORMS-ITERATION-HOOK* ITERATION-HOOK)
  236.               (*MAPFORMS-EXPAND-SUBSTS* EXPAND-SUBSTS)
  237.               (*MAPFORMS-BLOCK-NAMES* NIL)
  238.               (*MAPFORMS-GO-TAGS* NIL)
  239.               (*MAPFORMS-BLOCK-ALIST* NIL)
  240.               (*MAPFORMS-APPLY-FUNCTION* APPLY-FUNCTION)
  241.               (*MAPFORMS-STATE* INITIAL-STATE))
  242.   (DECLARE (SYS:DOWNWARD-FUNARG *MAPFORMS-FUNCTION*))
  243.   "Call a function on a form and all of its subforms.
  244.   The function is called on arguments subform, kind, usage, and state,
  245. and its first returned value is the new state.  If the second value is
  246. non-NIL the normal processing of this form is to be suppressed.
  247.   STATE is initially NIL unless the :INITIAL-STATE option is specified;
  248. the final state is returned as the value of MAPFORMS.
  249.   KIND is a symbol or list describing the subform (which can be a form or a
  250. variable being setq'ed or bound).
  251.   USAGE is a symbol describing the context in which the subform appears.
  252. The :USAGE option, defaulting to EVAL, is the usage for the top-level form.
  253.   If the :BOUND-VARIABLES option is specified, it is the initial value
  254. \(usually NIL) for *MAPFORMS-BOUND-VARIABLES*, the list of variables
  255. bound around the evaluation of each form.  If :BOUND-VARIABLES is not
  256. specified, the bookkeeping for bound variables is suppressed.
  257.   If the :APPLY-FUNCTION option is specified, it is a function called
  258. with the same arguments and values as the main processing function.  It sees
  259. each non-atomic form after its arguments or subforms have been processed.
  260.   If the :ITERATION-HOOK option is specified, it is a function called with
  261. an argument of T when an iteration is entered and NIL when it is left.
  262.   If the :EXPAND-SUBSTS option is specified, we look inside DEFSUBST bodies.
  263. Normally they are just assumed to behave like functions."
  264.   (COPYFORMS-1 FORM USAGE)
  265.   *MAPFORMS-STATE*)
  266.  
  267. (DEFUN COPYFORMS (*MAPFORMS-FUNCTION* FORM
  268.           &KEY (BOUND-VARIABLES 'NO-ENV)
  269.                (USAGE 'EVAL)
  270.                (APPLY-FUNCTION NIL)
  271.                (ITERATION-HOOK NIL)
  272.                (EXPAND-SUBSTS NIL)
  273.                (EXPAND-ALL-MACROS NIL)
  274.           &AUX (*COPYFORMS-FLAG* T)
  275.                (*MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT* NIL)
  276.                (*MAPFORMS-APPLY-FUNCTION* APPLY-FUNCTION)
  277.                (*MAPFORMS-ITERATION-HOOK* ITERATION-HOOK)
  278.                (*MAPFORMS-EXPAND-SUBSTS* EXPAND-SUBSTS)
  279.                (*MAPFORMS-BOUND-VARIABLES* BOUND-VARIABLES)
  280.                (*MAPFORMS-BLOCK-NAMES* NIL)
  281.                (*MAPFORMS-GO-TAGS* NIL)
  282.                (*MAPFORMS-BLOCK-ALIST* NIL)
  283.                (*COPYFORMS-EXPAND-ALL-MACROS* EXPAND-ALL-MACROS))
  284.   "Call a function on a form and all its subforms, possibly making
  285. substitutions.  The function is called on arguments subform, kind, and usage,
  286. and its returned value replaces the subform if it is not EQ.  If the second
  287. value is non-NIL the normal processing of this form is to be suppressed.
  288. Structure is copied as necessary to avoid smashing any of the original form.
  289.   KIND is a symbol or list describing the subform (which can be a form or a variable
  290. being setq'ed or bound).
  291.   USAGE is a symbol describing the context in which the subform appears.  The
  292. :USAGE option, defaulting to EVAL, is the usage for the top-level form.
  293.   If the :EXPAND-ALL-MACROS option is specified, macro-expansions will
  294. be copied into the result.  Otherwise, the original macro form will
  295. remain, unless something in the expansion was modified during copying.
  296.   If the :BOUND-VARIABLES option is specified, it is the initial value
  297. \(usually NIL) for *MAPFORMS-BOUND-VARIABLES*, the list of variables
  298. bound around the evaluation of each form.  If :BOUND-VARIABLES is not
  299. specified, the bookkeeping for bound variables is suppressed.
  300.   If the :APPLY-FUNCTION option is specified, it is a function called
  301. with the same arguments and values as the main processing function.  It sees
  302. each non-atomic form after its arguments or subforms have been processed.
  303. If it substitutes a new form, the new form will be analyzed and copied.
  304.   If the :ITERATION-HOOK option is specified, it is a function called with
  305. an argument of T when an iteration is entered and NIL when it is left."
  306.   (COPYFORMS-1 FORM USAGE))
  307.  
  308. ;;; Supporting macros
  309.  
  310. ;;; This macro allows substituting for some element of a list being
  311. ;;; mapped down, without smashing anything yet with minimal consing.
  312. ;;;    ORIGINAL-LIST - the original, uncopied list
  313. ;;;    CURRENT-LIST - that or a copy of it (must be a variable)
  314. ;;;    TAIL - must be a tail of CURRENT-LIST, its car is to be changed
  315. ;;; If TAIL is a variable, it is setq'ed to the corresponding tail of
  316. ;;; the copy if a copy is made.
  317. (DEFMACRO MAPFORMS-RPLACA (ORIGINAL-LIST CURRENT-LIST TAIL NEWCAR)
  318.   (OR (SYMBOLP CURRENT-LIST) (ERROR "~S not a variable" CURRENT-LIST))
  319.   (ONCE-ONLY (NEWCAR)
  320.     `(COND ((NEQ (CAR ,TAIL) ,NEWCAR)
  321.         (RPLACA (IF (EQ ,ORIGINAL-LIST ,CURRENT-LIST)
  322.             (MULTIPLE-VALUE-SETQ (,(AND (SYMBOLP TAIL) TAIL) ,CURRENT-LIST)
  323.               (MAPFORMS-RPLACA-COPY ,TAIL ,CURRENT-LIST))
  324.             ,TAIL)
  325.             ,NEWCAR)))))
  326.  
  327. (DEFUN MAPFORMS-RPLACA-COPY (TAIL LIST)
  328.   (LOOP WITH NEW-LIST = (COPY-LIST LIST)
  329.     FOR NEW-TAIL ON NEW-LIST AND OLD-TAIL ON LIST
  330.     WHEN (EQ OLD-TAIL TAIL)
  331.       RETURN (VALUES NEW-TAIL NEW-LIST)
  332.     FINALLY (ERROR "~S is not a tail of ~S" TAIL LIST)))
  333.  
  334. ;;; Same for cdr.
  335. ;;; Never stores back into TAIL (since of course it doesn't copy list beyond it)
  336. ;;; We assume that a given tail will only be rplacd'ed once
  337. (DEFMACRO MAPFORMS-RPLACD (ORIGINAL-LIST CURRENT-LIST TAIL NEWCDR)
  338.   (OR (SYMBOLP CURRENT-LIST) (ERROR "~S not a variable" CURRENT-LIST))
  339.   (ONCE-ONLY (NEWCDR)
  340.     `(COND ((NEQ (CDR ,TAIL) ,NEWCDR)
  341.         (RPLACD (IF (EQ ,ORIGINAL-LIST ,CURRENT-LIST)
  342.             (MULTIPLE-VALUE-SETQ (NIL ,CURRENT-LIST)
  343.               (MAPFORMS-RPLACD-COPY ,TAIL ,CURRENT-LIST))
  344.             ,TAIL)
  345.             ,NEWCDR)))))
  346.  
  347. ;Copy list through tail, but not into (cdr tail)
  348. (DEFUN MAPFORMS-RPLACD-COPY (TAIL LIST)
  349.   (LET* ((ORIGINAL-TAIL TAIL)
  350.      (ORIGINAL-LIST LIST)
  351.      (NEW-HEAD (CONS (CAR LIST) NIL))
  352.      (NEW-TAIL NEW-HEAD))
  353.     (LOOP DO
  354.       (WHEN (ATOM LIST)
  355.     (ERROR "~S is not a tail of ~S" ORIGINAL-TAIL ORIGINAL-LIST))
  356.       (RPLACD NEW-TAIL (CDR LIST))
  357.       (WHEN (EQ LIST TAIL)
  358.     (RETURN (VALUES NEW-TAIL NEW-HEAD)))
  359.       (SETQ LIST (CDR LIST))
  360.       (RPLACD NEW-TAIL (SETQ NEW-TAIL (CONS (CAR LIST) NIL))))))
  361.  
  362. ;;; Determine the KIND of a form (see the first page)
  363. ;;; As a second value we may return one of
  364. ;;;    LAMBDA - a lambda combination
  365. ;;;    NAMED-LAMBDA - a named-lambda combination
  366. ;;;    MACRO - a macro combination (for which there is no arg-template)
  367. ;;;    LAMBDA-MACRO - a lambda-macro combination
  368. ;;;    SYMBOL-MACRO - a symbol macro
  369. ;;;    SUBST - a defsubst (when checking for them is enabled)
  370. ;;;    some other atom - a special processing function, obtained from the
  371. ;;;      property of the function name whose indicator is our second argument
  372. (DEFUN CLASSIFY-FORM (FORM PROPERTY &AUX FCN TEM)
  373.   (DECLARE (VALUES KIND SPECIAL))
  374.   (COND ((ATOM FORM)
  375.      (COND ((CONSTANTP FORM)
  376.         'QUOTE)
  377.            ((PROPERTYP FORM 'SYMBOL-MACRO)
  378.         (VALUES NIL 'SYMBOL-MACRO))
  379.            ((PROPERTYP FORM 'ATOMIC-MACRO)    ;Old name
  380.         (VALUES NIL 'SYMBOL-MACRO))
  381.            (T 'SYMEVAL)))
  382.     ((EQ (SETQ FCN (CAR FORM)) 'QUOTE)
  383.      'QUOTE)
  384.     ((SYMBOLP FCN)
  385.      (COND ((SETQ TEM (CADR (ASSOC FCN (ENV-FUNCTIONS
  386.                         *MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*) :TEST #'EQ)))    ;second el of env is for functions
  387.         (COND ((EQ (CAR TEM) 'SPECIAL)
  388.                (VALUES NIL 'MACRO))
  389.               (T NIL)))
  390.            ((NOT (FBOUNDP FCN))
  391.         NIL)
  392.            ((OR #| (SETQ TEM (ASSOC 'ARG-TEMPLATE (DEBUGGING-INFO FCN))) |#
  393.             (SETQ TEM (ASSOC FCN *ARG-TEMPLATE-ALIST*)))
  394.         (VALUES TEM (AND PROPERTY (GET FCN PROPERTY))))
  395.            ((MACRO-FUNCTION FCN)
  396.         (VALUES NIL 'MACRO))
  397.            #| ((AND *MAPFORMS-EXPAND-SUBSTS*
  398.              (ASSOC 'SUBST-DEFINITION (DEBUGGING-INFO FCN)))
  399.         (VALUES NIL 'SUBST)) |#
  400.            ((FUNCTIONP FCN NIL)
  401.         NIL)
  402.            ((AND PROPERTY (SETQ TEM (GET FCN PROPERTY)))
  403.         (VALUES NIL TEM))
  404.            (T (FORM-NOT-UNDERSTOOD FORM "~S is a special form but lacks an arg-template"
  405.                         FCN)
  406.           NIL)))
  407.     ((AND (LISTP FCN) (MEMBER (CAR FCN) '(LAMBDA SUBST)))
  408.      (VALUES NIL 'LAMBDA))
  409.     ((AND (LISTP FCN) (MEMBER (CAR FCN) '(NAMED-LAMBDA NAMED-SUBST)))
  410.      (VALUES NIL 'NAMED-LAMBDA))
  411.     #|((LAMBDA-MACRO-CALL-P FCN)
  412.      (VALUES NIL 'LAMBDA-MACRO))|#
  413.     (T (FORM-NOT-UNDERSTOOD FORM "~S not understood in the function position of a form"
  414.                      FCN)
  415.        NIL)))
  416.  
  417. ;Not necessarily self-evaluating.  Just guaranteed always to evaluate to the same thing.
  418. ;--- Note that, unlike the compiler, we assume that defconstant's are not allowed
  419. ;--- to be shadowed by lexical or instance variables.  Common Lisp seems to allow
  420. ;--- such shadowing, except that since there is no unspecial declaration it is
  421. ;--- impossible to do, and it seems to discourage it by saying that the compiler
  422. ;--- may warn.  I would check for it here, but the environment is not available.
  423. ;--- In any case the CL CONSTANTP function is required to be true of such symbols.
  424. #-EXPLORER
  425. (DEFUN CONSTANTP (OBJECT)
  426.   (IF (ATOM OBJECT)
  427.       (OR (NOT (SYMBOLP OBJECT))
  428.       (NULL OBJECT)
  429.       (EQ OBJECT T)
  430.       (GET OBJECT 'DEFCONSTANT)
  431.       (KEYWORDP OBJECT))
  432.       (EQ (CAR OBJECT) 'QUOTE)))
  433.  
  434. (DEFUN VARIABLEP (X)
  435.   (AND (SYMBOLP X)
  436.        (NOT (CONSTANTP X))            ;better in Common Lisp
  437.        (NOT (PROPERTYP X 'SYMBOL-MACRO))
  438.        (NOT (PROPERTYP X 'ATOMIC-MACRO))    ;old name
  439.        ))
  440.  
  441. ;GET-PROPERTIES is an absolutely miserable replacement for GETL
  442. (DEFUN PROPERTYP (SYMBOL INDICATOR)
  443.   (LOOP FOR (I V) ON (SYMBOL-PLIST SYMBOL) BY 'CDDR
  444.     THEREIS (EQ I INDICATOR)))
  445.  
  446. ;;; Main driving functions
  447.  
  448. ;;; Process a form and its subforms, and return the new form
  449. ;;; (If not COPYFORMS, return the original form)
  450. ;;; The user function may call back into this if doing a COPYFORMS
  451. (DEFUN COPYFORMS-1 (ORIGINAL-FORM &OPTIONAL (USAGE 'EVAL))
  452.   ;; Loop as long as new forms are substituted
  453.   (LOOP WITH (KIND SPECIAL)
  454.     WITH FORM = ORIGINAL-FORM
  455.     WITH ORIGINAL-BEFORE-MACRO-EXPANSION = ORIGINAL-FORM
  456.     WITH DONE-FLAG        ;Flags considered harmful: used for two purposes, too!
  457.     WITH NEW-FORM DO
  458.     (MULTIPLE-VALUE-SETQ (KIND SPECIAL) (CLASSIFY-FORM FORM 'MAPFORMS))
  459.     ;; Tell the client about this form.
  460.     ;; It may replace the form or override normal subform processing.
  461.     (MULTIPLE-VALUE-SETQ (NEW-FORM DONE-FLAG) (MAPFORMS-CALL FORM KIND USAGE))
  462.     ;; Process the form accordingly, and set DONE-FLAG if loop should terminate
  463.     (COND ((NEQ NEW-FORM FORM) (SETQ FORM NEW-FORM))    ;Again, with substituted form
  464.       (DONE-FLAG)                    ;Bypass normal processing
  465.       ((OR (EQ SPECIAL 'MACRO)            ;Any kind of macro
  466.            #|(EQ SPECIAL 'LAMBDA-MACRO)|#
  467.            (EQ SPECIAL 'SYMBOL-MACRO)
  468.            (EQ SPECIAL 'SUBST))
  469.        (LET ((EXPANSION (CASE SPECIAL
  470.                   ((MACRO SYMBOL-MACRO SUBST)
  471.                    (MACROEXPAND-1 FORM *MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*))
  472.                   #|(LAMBDA-MACRO
  473.                 (CONS (LAMBDA-MACRO-EXPAND (CAR FORM)) (CDR FORM)))|#)))
  474.          (AND (EQ ORIGINAL-FORM FORM)
  475.           (SETQ ORIGINAL-FORM EXPANSION))
  476.          (SETQ FORM EXPANSION)))
  477.       ((OR (EQ SPECIAL 'LAMBDA) (EQ SPECIAL 'NAMED-LAMBDA))    ;Lambda-combination
  478.        (LET ((LAMBDA-LIST (IF (EQ SPECIAL 'NAMED-LAMBDA) (CDDAR FORM) (CDAR FORM))))
  479.          ;; Check for lambda-list keywords that would mean abnormal argument evaluation.
  480.          (IF (MEMBER '"E LAMBDA-LIST)
  481.          (FORM-NOT-UNDERSTOOD FORM ""E appears in the lambda list"))
  482.          ;; First process the arguments.
  483.          (SETQ FORM (MAPFORMS-LIST ORIGINAL-FORM FORM (CDR FORM) 'EVAL 'EVAL))
  484.          ;; Now process the bindings and then the body
  485.          (MAPFORMS-RPLACA ORIGINAL-FORM FORM
  486.                   FORM (MAPFORMS-LAMBDA (CAR FORM) (CAR FORM) LAMBDA-LIST USAGE))
  487.          (SETQ DONE-FLAG T)))
  488.       (SPECIAL                    ;General escape
  489.        (SETQ FORM (FUNCALL SPECIAL ORIGINAL-FORM FORM USAGE))
  490.        (SETQ DONE-FLAG T))
  491.       ((NULL KIND)                    ;Ordinary function, do args
  492.        (SETQ FORM (MAPFORMS-LIST ORIGINAL-FORM FORM (CDR FORM) 'EVAL 'EVAL))
  493.        (SETQ DONE-FLAG T))
  494.       ((LISTP KIND)                    ;Template-driven meta-eval
  495.        (LET ((TEMPLATE (CDR KIND)))
  496.          (AND (LISTP TEMPLATE)
  497.           (MEMBER (CAR TEMPLATE) '(COND LOOP))
  498.           (SETQ TEMPLATE (CDR TEMPLATE)))    ;Remove flags uninteresting here
  499.          (SETQ FORM (MAPFORMS-TEMPLATE ORIGINAL-FORM FORM TEMPLATE USAGE))
  500.          (SETQ DONE-FLAG T)))
  501.       (T (SETQ DONE-FLAG T)))            ;No subforms
  502.     ;; Now decide whether to return what we have or process it again
  503.     (AND DONE-FLAG
  504.      (OR (ATOM FORM)
  505.          (NULL *MAPFORMS-APPLY-FUNCTION*)
  506.          (EQ FORM (SETQ FORM
  507.                 (MULTIPLE-VALUE-SETQ (NIL DONE-FLAG)
  508.                   (MAPFORMS-CALL FORM KIND USAGE *MAPFORMS-APPLY-FUNCTION*))))
  509.          DONE-FLAG)
  510.      (RETURN (IF (AND (EQ FORM ORIGINAL-FORM)
  511.               (NOT *COPYFORMS-EXPAND-ALL-MACROS*))
  512.              ORIGINAL-BEFORE-MACRO-EXPANSION    ;Undo uninteresting macro expansion
  513.              FORM)))))                ;Replacement or original form
  514.  
  515. ;;; The user function may call back into this if doing a MAPFORMS
  516. (DEFUN MAPFORMS-1 (FORM &OPTIONAL (USAGE 'EVAL))
  517.   (COPYFORMS-1 FORM USAGE)
  518.   *MAPFORMS-STATE*)
  519.  
  520. ;;; Call the user function on this form, and return the new form
  521. (DEFUN MAPFORMS-CALL (FORM KIND USAGE &OPTIONAL (FUNCTION *MAPFORMS-FUNCTION*) &AUX FLAG)
  522.   (COND (*COPYFORMS-FLAG*
  523.      (FUNCALL FUNCTION FORM KIND USAGE))
  524.     (T
  525.      (MULTIPLE-VALUE-SETQ (*MAPFORMS-STATE* FLAG)
  526.        (FUNCALL FUNCTION FORM KIND USAGE *MAPFORMS-STATE*))
  527.      (VALUES FORM FLAG))))
  528.  
  529. ;;; Process the rest of the forms in a list.  Return the original list or a copy
  530. ;;; of it with substitutions made.
  531. (DEFUN MAPFORMS-LIST (ORIGINAL-LIST CURRENT-LIST TAIL-TO-DO ALL-BUT-LAST-USAGE LAST-USAGE)
  532.   (LOOP FOR TAIL ON TAIL-TO-DO DO
  533.     (MAPFORMS-RPLACA ORIGINAL-LIST CURRENT-LIST
  534.         TAIL (COPYFORMS-1 (CAR TAIL) (IF (CDR TAIL) ALL-BUT-LAST-USAGE LAST-USAGE))))
  535.   CURRENT-LIST)
  536.  
  537. ;;; Pass over documentation strings and local declarations, and return three values:
  538. ;;;    New value of CURRENT-LIST
  539. ;;;    New value of TAIL
  540. ;;;    New value of LOCAL-DECLARATIONS
  541. (DEFUN MAPFORMS-DECLARE (ORIGINAL-LIST CURRENT-LIST TAIL &AUX (DECLARATIONS NIL))
  542.   (LOOP DOING
  543.     (COND ((NULL TAIL) (RETURN))
  544.       ((AND (CDR TAIL) (STRINGP (CAR TAIL))))    ;Doc string
  545.       ((AND (LISTP (CAR TAIL)) (EQ (CAAR TAIL) 'DECLARE))
  546.        (LOOP WITH ORIGINAL = (CAR TAIL)        ;Map over each declaration
  547.          WITH CURRENT = ORIGINAL
  548.          FOR DCLS ON (CDR ORIGINAL)
  549.          DO (MAPFORMS-RPLACA ORIGINAL CURRENT
  550.                      DCLS (MAPFORMS-CALL (CAR DCLS) 'DECLARE 'DECLARE))
  551.          FINALLY (MAPFORMS-RPLACA ORIGINAL-LIST CURRENT-LIST TAIL CURRENT)
  552.              (SETQ DECLARATIONS (APPEND (CDR CURRENT) DECLARATIONS))))
  553.       (T (RETURN)))                    ;Start of real body
  554.     (POP TAIL))
  555.   (VALUES CURRENT-LIST TAIL (NCONC DECLARATIONS LOCAL-DECLARATIONS)))
  556.  
  557. ;;; Process a lambda-expression, or any function body
  558. (DEFUN MAPFORMS-LAMBDA (ORIGINAL-LAMBDA LAMBDA ARGS-AND-BODY USAGE)
  559.   (LET ((*MAPFORMS-BOUND-VARIABLES* *MAPFORMS-BOUND-VARIABLES*))
  560.     (MULTIPLE-VALUE-BIND (LAMBDA ARGS-AND-BODY LOCAL-DECLARATIONS)
  561.     (MAPFORMS-DECLARE ORIGINAL-LAMBDA LAMBDA ARGS-AND-BODY)
  562.       (MAPFORMS-RPLACA ORIGINAL-LAMBDA LAMBDA ARGS-AND-BODY
  563.     (LOOP WITH LAMBDA-LIST = (CAR ARGS-AND-BODY)
  564.           WITH ORIGINAL-LAMBDA-LIST = LAMBDA-LIST
  565.           FOR LL ON LAMBDA-LIST
  566.           DO (OR (MEMBER (CAR LL) LAMBDA-LIST-KEYWORDS)
  567.              (MAPFORMS-RPLACA ORIGINAL-LAMBDA-LIST LAMBDA-LIST
  568.                       LL (MAPFORMS-BIND (CAR LL) NIL T LAMBDA)))
  569.           FINALLY (RETURN LAMBDA-LIST)))
  570.       (MAPFORMS-LIST ORIGINAL-LAMBDA LAMBDA (CDR ARGS-AND-BODY) 'EFFECT USAGE))))
  571.  
  572. ;; Process a single binding
  573. ;; which may be VAR, (VAR), or (VAR VAL)
  574. ;; ALLOW-SUPPLIED-P is NIL normally
  575. ;;               T to allow (var val flag-var)
  576. ;;               IGNORE to allow (var val . anything)
  577. ;;--- Doesn't handle separate LOCAL-DECLARATIONS for the variable and the init form
  578. (DEFUN MAPFORMS-BIND (BIND PARALLEL-BINDING-P ALLOW-SUPPLIED-P CONTAINING-FORM
  579.               &AUX (ORIGINAL-BIND BIND) (VAR1 NIL) (VAR2 NIL))
  580.   (COND ((SYMBOLP BIND)
  581.      (SETQ BIND (SETQ VAR1 (MAPFORMS-CALL BIND 'LET 'LET))))
  582.     ((ATOM BIND)
  583.      (FORM-NOT-UNDERSTOOD CONTAINING-FORM
  584.                   "~S appears where a bound variable should be" BIND))
  585.     ((NOT (SYMBOLP (CAR BIND)))
  586.      (FORM-NOT-UNDERSTOOD CONTAINING-FORM
  587.                   "~S appears where a bound variable should be" (CAR BIND)))
  588.     (T
  589.      (MAPFORMS-RPLACA ORIGINAL-BIND BIND
  590.               BIND (SETQ VAR1 (MAPFORMS-CALL (CAR BIND) 'LET 'LET)))
  591.      (WHEN (CDR BIND)
  592.        ;; Init form or default value for optional argument
  593.        (MAPFORMS-RPLACA ORIGINAL-BIND BIND (CDR BIND) (COPYFORMS-1 (CADR BIND) 'EVAL))
  594.        (COND ((NULL (CDDR BIND)))
  595.          ((OR (CDDDR BIND) (NOT ALLOW-SUPPLIED-P))
  596.           (FORM-NOT-UNDERSTOOD CONTAINING-FORM
  597.                        "~S is too long to be a list of variable and value"
  598.                        BIND))
  599.          ((EQ ALLOW-SUPPLIED-P 'IGNORE))
  600.          ((NOT (SYMBOLP (CADDR BIND)))
  601.           (FORM-NOT-UNDERSTOOD CONTAINING-FORM
  602.                        "~S appears where a supplied-p variable should be"
  603.                        (CADDR BIND)))
  604.          (T ;; Optional argument supplied-p-flag variable
  605.           (MAPFORMS-RPLACA ORIGINAL-BIND BIND (CDDR BIND)
  606.                    (SETQ VAR2 (MAPFORMS-CALL (CADDR BIND) 'LET 'LET))))))))
  607.   (COND ((EQ *MAPFORMS-BOUND-VARIABLES* 'NO-ENV))
  608.     (PARALLEL-BINDING-P
  609.      (AND VAR1 (PUSH VAR1 *MAPFORMS-PARALLEL-BINDS*))
  610.      (AND VAR2 (PUSH VAR2 *MAPFORMS-PARALLEL-BINDS*)))
  611.     (T
  612.      (AND VAR1 (PUSH VAR1 *MAPFORMS-BOUND-VARIABLES*))
  613.      (AND VAR2 (PUSH VAR2 *MAPFORMS-BOUND-VARIABLES*))))
  614.   BIND)
  615.  
  616. ;;; Template-directed driving function
  617.  
  618. (DEFVAR *MAPFORMS-TEMPLATE-USAGE*)    ;USAGE of the whole form being processed
  619. (DEFVAR *MAPFORMS-TEMPLATE-FORM*)    ;Original of the whole form
  620.  
  621. (DEFUN MAPFORMS-TEMPLATE (ORIGINAL-FORM *MAPFORMS-TEMPLATE-FORM*
  622.               TEMPLATE *MAPFORMS-TEMPLATE-USAGE*)
  623.   (MAPFORMS-RPLACD ORIGINAL-FORM *MAPFORMS-TEMPLATE-FORM*
  624.     *MAPFORMS-TEMPLATE-FORM*
  625.     (LET ((*MAPFORMS-BOUND-VARIABLES* *MAPFORMS-BOUND-VARIABLES*)
  626.           (LOCAL-DECLARATIONS LOCAL-DECLARATIONS))
  627.       (MAPFORMS-TEMPLATE-1 (CDR *MAPFORMS-TEMPLATE-FORM*) TEMPLATE)))
  628.   *MAPFORMS-TEMPLATE-FORM*)
  629.  
  630. ;;; May return a modified version of ARGL, which the caller rplac's into his (sub)form
  631. ;;; This function is recursive in the car direction and iterative in the cdr
  632. ;;; ARGL is some piece of the original form (initially the cdr), not necessarily a list
  633. (DEFUN MAPFORMS-TEMPLATE-1 (ORIGINAL-ARGL TEMPLATE)
  634.   (LOOP WITH CURRENT-ARGL = ORIGINAL-ARGL
  635.     WITH TAIL = NIL
  636.     WITH ARGL = ORIGINAL-ARGL DO
  637.     (COND ((NULL TEMPLATE)
  638.        (IF ARGL
  639.            (FORM-NOT-UNDERSTOOD *MAPFORMS-TEMPLATE-FORM*
  640.                     "~S are extra arguments not allowed for by the template"
  641.                     ARGL))
  642.        (LOOP-FINISH))
  643.  
  644.       ;; The following template items match single subforms
  645.       ((MEMBER TEMPLATE '(QUOTE GO RETURN-FROM SET SYMEVAL))
  646.        (SETQ ARGL (MAPFORMS-CALL ARGL TEMPLATE TEMPLATE))
  647.        (LOOP-FINISH))
  648.       ((EQ TEMPLATE 'LET)
  649.        (SETQ ARGL (MAPFORMS-BIND ARGL NIL NIL *MAPFORMS-TEMPLATE-FORM*))
  650.        (LOOP-FINISH))
  651.       ((EQ TEMPLATE 'PARALLEL-LET)
  652.        (LET ((*MAPFORMS-PARALLEL-BINDS* NIL))
  653.          (LOOP WHILE ARGL DO
  654.            (MAPFORMS-RPLACA ORIGINAL-ARGL CURRENT-ARGL ARGL
  655.                 (MAPFORMS-BIND (CAR ARGL) T NIL *MAPFORMS-TEMPLATE-FORM*))
  656.            (SETQ TAIL ARGL ARGL (CDR ARGL)))
  657.          (SETQ *MAPFORMS-BOUND-VARIABLES*
  658.            (NCONC *MAPFORMS-PARALLEL-BINDS* *MAPFORMS-BOUND-VARIABLES*)))
  659.        (LOOP-FINISH))
  660.       ((EQ TEMPLATE 'CALL)
  661.        (SETQ ARGL (MAPFORMS-CALL ARGL 'QUOTE TEMPLATE))
  662.        (LOOP-FINISH))
  663.       ((ATOM TEMPLATE)
  664.        (CASE TEMPLATE
  665.          ((BODY)
  666.           (RETURN (MAPFORMS-LIST ORIGINAL-ARGL CURRENT-ARGL
  667.                      ARGL 'EFFECT *MAPFORMS-TEMPLATE-USAGE*)))
  668.          ((PROG)
  669.           (LET ((*MAPFORMS-GO-TAGS*
  670.               (AND (NEQ *MAPFORMS-BOUND-VARIABLES* 'NO-ENV)
  671.                (NCONC (LOOP FOR STMT IN ARGL
  672.                     WHEN (ATOM STMT) COLLECT STMT)
  673.                   *MAPFORMS-GO-TAGS*)))
  674.             (ITERATION NIL))
  675.         (LOOP FOR TAIL ON ARGL AS STMT = (CAR TAIL) DO
  676.           (IF (ATOM STMT)
  677.               ;; First tag is start of possibly iterated code
  678.               ;; We aren't smart enough to worry about tags reached
  679.               ;; only by forward branches.
  680.               (UNLESS ITERATION
  681.             (WHEN *MAPFORMS-ITERATION-HOOK*
  682.               (FUNCALL *MAPFORMS-ITERATION-HOOK* T))
  683.             (SETQ ITERATION T))
  684.               ;; Lists are forms evaluated for effect
  685.               (MAPFORMS-RPLACA ORIGINAL-ARGL CURRENT-ARGL
  686.                        TAIL (COPYFORMS-1 STMT 'EFFECT))))
  687.         (AND ITERATION
  688.              *MAPFORMS-ITERATION-HOOK*
  689.              (FUNCALL *MAPFORMS-ITERATION-HOOK* NIL))
  690.         (RETURN CURRENT-ARGL)))
  691.          ((RETURN)
  692.           (SETQ ARGL (COPYFORMS-1 ARGL *MAPFORMS-TEMPLATE-USAGE*))
  693.           (LOOP-FINISH))
  694.          ((EVAL TEST EFFECT SMASH PROP FUNCTION)
  695.           (SETQ ARGL (COPYFORMS-1 ARGL TEMPLATE))
  696.           (LOOP-FINISH))
  697.          (OTHERWISE
  698.           (ERROR "Malformed template: ~S trying to match ~S in a ~S-form"
  699.              TEMPLATE ARGL (CAR *MAPFORMS-TEMPLATE-FORM*)))))
  700.       ((EQ (CAR TEMPLATE) 'AND)
  701.        (DOLIST (TEMPLATE (CDR TEMPLATE))
  702.          (SETQ ARGL (MAPFORMS-TEMPLATE-1 ARGL TEMPLATE)))
  703.        (LOOP-FINISH))
  704.       ((EQ (CAR TEMPLATE) 'IF)
  705.        (SETQ ARGL (MAPFORMS-TEMPLATE-1 ARGL
  706.             (IF (IF (ATOM (SECOND TEMPLATE)) (FUNCALL (SECOND TEMPLATE) ARGL)
  707.                 (LET ((EXPR ARGL))
  708.                   (DECLARE (SPECIAL EXPR))
  709.                   (EVAL (SECOND TEMPLATE))))
  710.                 (THIRD TEMPLATE)
  711.                 (FOURTH TEMPLATE))))
  712.        (LOOP-FINISH))
  713.       ((EQ (CAR TEMPLATE) 'MACRO)
  714.        (LET ((EXPR ARGL))
  715.          (DECLARE (SPECIAL EXPR))
  716.          (SETQ ARGL (MAPFORMS-TEMPLATE-1 (EVAL (SECOND TEMPLATE))
  717.                          (EVAL (THIRD TEMPLATE)))))
  718.        (LOOP-FINISH))
  719.  
  720.       ;; The following template items match a variable number of subforms (or none)
  721.       ;; COND and LOOP should have been POP'ed off before we ever get here
  722.       ((EQ (CAR TEMPLATE) 'DECLARE)
  723.        (MULTIPLE-VALUE-SETQ (CURRENT-ARGL ARGL LOCAL-DECLARATIONS)
  724.          (MAPFORMS-DECLARE ORIGINAL-ARGL CURRENT-ARGL ARGL))
  725.        (SETQ TEMPLATE (CDR TEMPLATE)))
  726.       ((EQ (CAR TEMPLATE) 'BLOCK)
  727.        (MAPFORMS-RPLACD ORIGINAL-ARGL ARGL ARGL
  728.                 (MAPFORMS-BLOCK (CAR ARGL) (CDR ARGL) (CDR TEMPLATE)))
  729.        (LOOP-FINISH))
  730.       ((EQ (CAR TEMPLATE) 'ANONYMOUS-BLOCK)
  731.        (SETQ ARGL (MAPFORMS-BLOCK NIL ARGL (CDR TEMPLATE)))
  732.        (LOOP-FINISH))
  733.       ((EQ (CAR TEMPLATE) 'ARBITRARY)
  734.        (MAPFORMS-CALL (CAR *MAPFORMS-TEMPLATE-FORM*) 'ARBITRARY 'ARBITRARY)
  735.        (SETQ TEMPLATE (CDR TEMPLATE)))
  736.       ((NULL ARGL) (LOOP-FINISH))
  737.       ((AND (LISTP (CAR TEMPLATE))
  738.         (EQ (CAAR TEMPLATE) 'REPEAT))
  739.        (LOOP REPEAT (MAPFORMS-REPEAT-CHECK TEMPLATE ARGL (CDAR TEMPLATE)) DO
  740.          (LOOP FOR TEM IN (CDAR TEMPLATE) DO
  741.            (MAPFORMS-RPLACA ORIGINAL-ARGL CURRENT-ARGL
  742.                 ARGL (MAPFORMS-TEMPLATE-1 (CAR ARGL) TEM))
  743.            (SETQ TAIL ARGL ARGL (CDR ARGL))))
  744.        (SETQ TEMPLATE (CDR TEMPLATE)))
  745.       ((AND (LISTP (CAR TEMPLATE))
  746.         (EQ (CAAR TEMPLATE) 'ORDER))
  747.        ;; First match up templates with forms, special-casing REPEAT
  748.        ;; Each element of FORMS is a form, or a list of forms to repeat through
  749.        ;; Each element of QUEUE is a list (priority template cons-of-FORMS)
  750.        (LOOP FOR X IN (CDAR TEMPLATE) WITH L = ARGL
  751.          AS N = (FIRST X) AND TEM = (SECOND X)
  752.          COLLECT
  753.            (COND ((AND (LISTP TEM) (EQ (CAR TEM) 'REPEAT))
  754.               (LET ((REPEAT (MAPFORMS-REPEAT-CHECK TEMPLATE ARGL
  755.                                    (CDR TEM) (CDDAR TEMPLATE))))
  756.                 (SETQ TEM (CDR X))    ;((REPEAT t t...))
  757.                 (LDIFF L (SETQ L (NTHCDR (* REPEAT (LIST-LENGTH (CDAR TEM)))
  758.                              L)))))
  759.              (L (POP L))
  760.              (T (FORM-NOT-UNDERSTOOD *MAPFORMS-TEMPLATE-FORM*
  761.                     "Wrong length list: matching ~S to template ~S"
  762.                     ARGL TEMPLATE)
  763.                 NIL))
  764.            INTO FORMS
  765.         COLLECT (LIST N TEM (LAST FORMS)) INTO QUEUE
  766.         FINALLY
  767.         ;; Process the forms and templates in evaluation order
  768.         (LOOP FOR (N TEM FORM-LOC) IN (SORT QUEUE #'< :KEY #'CAR) DO
  769.           (RPLACA FORM-LOC (MAPFORMS-TEMPLATE-1 (CAR FORM-LOC) TEM)))
  770.         ;; Store the resulting forms back into ARGL
  771.         (LOOP FOR (N TEM) IN (CDAR TEMPLATE) AND FORM IN FORMS DO
  772.           (COND ((AND (LISTP TEM) (EQ (CAR TEM) 'REPEAT))
  773.              (DOLIST (FORM FORM)
  774.                (MAPFORMS-RPLACA ORIGINAL-ARGL CURRENT-ARGL ARGL FORM)
  775.                (SETQ TAIL ARGL ARGL (CDR ARGL))))
  776.             (T (MAPFORMS-RPLACA ORIGINAL-ARGL CURRENT-ARGL ARGL FORM)
  777.                (SETQ TAIL ARGL ARGL (CDR ARGL))))))
  778.        (SETQ TEMPLATE (CDR TEMPLATE)))
  779.  
  780.       ;; Not a leaf.  Destructure into the car and cdr of the trees.
  781.       (T (MAPFORMS-RPLACA ORIGINAL-ARGL CURRENT-ARGL
  782.                   ARGL (MAPFORMS-TEMPLATE-1 (CAR ARGL) (CAR TEMPLATE)))
  783.          (SETQ TAIL ARGL ARGL (CDR ARGL))
  784.          (SETQ TEMPLATE (CDR TEMPLATE))))
  785.     FINALLY (RETURN (COND ((NULL TAIL) ARGL)
  786.               (T (MAPFORMS-RPLACD ORIGINAL-ARGL CURRENT-ARGL TAIL ARGL)
  787.                  CURRENT-ARGL)))))
  788.  
  789. ;;; Call the template processor inside a binding of *MAPFORMS-BLOCK-ALIST*
  790. ;;; with a new pair on the front.
  791. (DEFUN MAPFORMS-BLOCK (NAME BODY TEMPLATE)
  792.   (WITH-STACK-LIST* (PAIR NAME *MAPFORMS-TEMPLATE-USAGE*)
  793.     (WITH-STACK-LIST* (*MAPFORMS-BLOCK-ALIST* PAIR *MAPFORMS-BLOCK-ALIST*)
  794.       (LET ((*MAPFORMS-BLOCK-NAMES* (AND (NEQ *MAPFORMS-BOUND-VARIABLES* 'NO-ENV)
  795.                      (CONS NAME *MAPFORMS-BLOCK-NAMES*))))
  796.     (MAPFORMS-TEMPLATE-1 BODY TEMPLATE)))))
  797.  
  798. ;;; Decide how much of the form a REPEAT should match (return number of repetitions)
  799. (DEFUN MAPFORMS-REPEAT-CHECK (TEMPLATE ARGL SUBTEMPLATE &OPTIONAL MORE-TEMPLATE)
  800.   ;; Some error checking because these templates are so hairy
  801.   (DOLIST (HAIR '(DECLARE BLOCK ANONYMOUS-BLOCK LOOP COND ARBITRARY))
  802.     (AND (MEMBER HAIR (CDR TEMPLATE))
  803.      (ERROR "Malformed template for ~S: ~S can't figure out how ~@
  804.          much of ~S to match because there is a ~S to its right."
  805.         (CAR *MAPFORMS-TEMPLATE-FORM*) (CAAR TEMPLATE) ARGL HAIR)))
  806.   (DOLIST (HAIR '(REPEAT ORDER))
  807.     (AND (CAREFUL-ASSOC HAIR (CDR TEMPLATE))
  808.      (ERROR "Malformed template for ~S: ~S can't figure out how ~@
  809.          much of ~S to match because there is a ~S to its right."
  810.         (CAR *MAPFORMS-TEMPLATE-FORM*) (CAAR TEMPLATE) ARGL HAIR)))
  811.   (DOLIST (HAIR '(DECLARE BLOCK ANONYMOUS-BLOCK LOOP COND ARBITRARY))
  812.     (AND (MEMBER HAIR SUBTEMPLATE)
  813.      (ERROR "Malformed template for ~S: ~S can't figure out how ~@
  814.          much of ~S to match because there is a ~S in the repeated part."
  815.         (CAR *MAPFORMS-TEMPLATE-FORM*) (CAAR TEMPLATE) ARGL HAIR)))
  816.   (DOLIST (HAIR '(REPEAT ORDER))
  817.     (AND (CAREFUL-ASSOC HAIR SUBTEMPLATE)
  818.      (ERROR "Malformed template for ~S: ~S can't figure out how ~@
  819.          much of ~S to match because there is a ~S in the repeated part."
  820.         (CAR *MAPFORMS-TEMPLATE-FORM*) (CAAR TEMPLATE) ARGL HAIR)))
  821.   ;; Decide number of repetitions
  822.   (LET ((TLEN (LIST-LENGTH SUBTEMPLATE))    ;Number of repeated items
  823.     (LEN (- (LIST-LENGTH ARGL)        ;Number of matching args
  824.         (LIST-LENGTH (CDR TEMPLATE)) 
  825.         (LIST-LENGTH MORE-TEMPLATE))))
  826.     (OR (ZEROP (MOD LEN TLEN))
  827.     (FORM-NOT-UNDERSTOOD *MAPFORMS-TEMPLATE-FORM*
  828.                  "Wrong length list: matching ~S to template ~S leaves ~D extra"
  829.                  ARGL TEMPLATE (MOD LEN TLEN)))
  830.     (FLOOR LEN TLEN)))
  831.  
  832. ;I can't use any Common Lisp functions for this, because L may be a "dotted"
  833. ;list rather than a true list.
  834. (DEFUN CAREFUL-ASSOC (X L)
  835.   (DO ((L L (CDR L)))
  836.       ((ATOM L) NIL)
  837.     (AND (LISTP (CAR L))
  838.      (EQL (CAAR L) X)
  839.      (RETURN (CAR L)))))
  840.  
  841. ;;; Error reporting
  842.  
  843. #+LISPM (PROGN 'COMPILE        ;Common Lisp doesn't have conditions yet
  844.  
  845. ;Flavor definition put first to defeat signal compiler warning
  846. (DEFFLAVOR FORM-NOT-UNDERSTOOD (FORM FORMAT-STRING FORMAT-ARGS COPYFORMS-FLAG)
  847.        (DBG:NO-ACTION-MIXIN ZL:ERROR)
  848.   (:INITABLE-INSTANCE-VARIABLES FORM FORMAT-STRING FORMAT-ARGS)
  849.   (:GETTABLE-INSTANCE-VARIABLES FORM))
  850.  
  851. ;All errors are signalled by calling this function, which signals
  852. ;the condition of the same name.  Normally goes to the debugger,
  853. ;but the caller of MAPFORMS may establish a handler.
  854. ;This function might work differently in other Lisp implementations.
  855. (DEFUN FORM-NOT-UNDERSTOOD (FORM FORMAT-STRING &REST FORMAT-ARGS)
  856.   (SIGNAL 'FORM-NOT-UNDERSTOOD :FORM FORM
  857.                    :FORMAT-STRING FORMAT-STRING
  858.                    :FORMAT-ARGS (COPY-LIST FORMAT-ARGS)
  859.                    :PROCEED-TYPES '(:NO-ACTION)))
  860.  
  861. (DEFPROP FORM-NOT-UNDERSTOOD T :ERROR-REPORTER)
  862.  
  863. (DEFMETHOD (FORM-NOT-UNDERSTOOD :AFTER :INIT) (IGNORE)
  864.   (SETQ COPYFORMS-FLAG *COPYFORMS-FLAG*))
  865.  
  866. (DEFMETHOD (FORM-NOT-UNDERSTOOD :REPORT) (STREAM)
  867.   (FORMAT STREAM "~:[MAPFORMS~;COPYFORMS~] was unable to understand the form ~S.~%~1{~}"
  868.       COPYFORMS-FLAG FORM FORMAT-STRING FORMAT-ARGS))
  869.  
  870. (COMPILE-FLAVOR-METHODS FORM-NOT-UNDERSTOOD)
  871. );#+LISPM
  872.  
  873. #-LISPM                ;This will work in straight Common Lisp
  874. (DEFUN FORM-NOT-UNDERSTOOD (FORM FORMAT-STRING &REST FORMAT-ARGS)
  875.   (ERROR "~:[MAPFORMS~;COPYFORMS~] was unable to understand the form ~S.~%~1{~}"
  876.       COPYFORMS-FLAG FORM FORMAT-STRING FORMAT-ARGS))
  877.  
  878. ;;; Knowledge of special forms that has to be procedural
  879.  
  880. (DEFUN (:PROPERTY MACROLET MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  881.   (WITH-STACK-LIST (*MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*
  882.              NIL (ENV-FUNCTIONS *MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*))
  883.     ;; I think it is improper to walk the expanders --BSG
  884.     (LOOP FOR MACRO IN (CADR FORM)
  885.       DO (PUSH (MACROEXPAND MACRO *MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*)
  886.            (ENV-FUNCTIONS *MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*)))
  887.     (MAPFORMS-LIST ORIGINAL-FORM FORM (CDDR FORM) 'EFFECT USAGE)))
  888.  
  889. (DEFUN (:PROPERTY FLET MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  890.   (MAPFORMS-FLET-LABELS ORIGINAL-FORM FORM USAGE))
  891.  
  892. (DEFUN (:PROPERTY LABELS MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  893.   (MAPFORMS-FLET-LABELS ORIGINAL-FORM FORM USAGE))
  894.  
  895. (DEFUN MAPFORMS-FLET-LABELS (ORIGINAL-FORM FORM USAGE)
  896.   (WITH-STACK-LIST (*MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*
  897.              NIL (ENV-FUNCTIONS *MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*))
  898.     (FLET ((WALK-DEFINITIONS ()
  899.           (LOOP WITH FUNCL = (CADR FORM)
  900.             WITH CURRENT-FUNCL = FUNCL
  901.             FOR DEFS ON FUNCL
  902.             AS (LAMBDA) = DEFS
  903.             DO (MAPFORMS-RPLACA
  904.              FUNCL CURRENT-FUNCL
  905.              DEFS (MAPFORMS-LAMBDA LAMBDA LAMBDA (CDR LAMBDA) 'EVAL))
  906.             FINALLY  (MAPFORMS-RPLACA ORIGINAL-FORM FORM (CDR FORM) CURRENT-FUNCL)))
  907.        (ADD-DEFINITIONS-TO-ENVIRONMENT ()
  908.               (LOOP FOR (FUNCTION) IN (CADR FORM)
  909.             DO (PUSH (LIST
  910.                    FUNCTION
  911.                    (LIST #'(LAMBDA (&REST IGNORE)
  912.                      (ERROR
  913.                        "Can't call lexical function ~S at compile time."
  914.                        FUNCTION))))    ;Get it?
  915.                  (ENV-FUNCTIONS *MAPFORMS-LEXICAL-FUNCTION-ENVIRONMENT*)))))
  916.       (CASE (CAR ORIGINAL-FORM)
  917.     (LABELS
  918.       (ADD-DEFINITIONS-TO-ENVIRONMENT)
  919.       (WALK-DEFINITIONS))
  920.     (FLET
  921.       (WALK-DEFINITIONS)
  922.       (ADD-DEFINITIONS-TO-ENVIRONMENT))))
  923.       
  924.     (MAPFORMS-LIST ORIGINAL-FORM FORM (CDDR FORM) 'EFFECT USAGE)))
  925.  
  926. ;Must be procedural to get bindings wrapped around it
  927. (DEFUN (:PROPERTY COMPILER-LET MAPFORMS) (IGNORE FORM USAGE)
  928.   (LET ((NEW-BODY (COMPILER-LET-INTERNAL (CADR FORM) (CDDR FORM) #'COPYFORMS-1 USAGE)))
  929.     ;; If the body was altered, build a new whole form to contain it, else return original
  930.     (IF (NULL (CDDDR FORM))
  931.     (IF (EQ NEW-BODY (CADDR FORM))
  932.         FORM
  933.         `(COMPILER-LET ,(CADR FORM) ,NEW-BODY))
  934.     ;; Take back apart the progn 'compile built by compiler-let-internal
  935.     (COND ((EQ (CDDR NEW-BODY) (CDDR FORM))
  936.            FORM)
  937.           ((AND (LISTP NEW-BODY)
  938.             (EQ (CAR NEW-BODY) 'PROGN)
  939.             (EQUAL (CADR NEW-BODY) ''COMPILE))
  940.            `(COMPILER-LET ,(CADR FORM) . ,(CDDR NEW-BODY)))
  941.           (T `(COMPILER-LET ,(CADR FORM) ,NEW-BODY))))))
  942.  
  943. ;These must be procedural to lookup the usage of the block being returned from
  944. ;--- This is the ZL definition of RETURN block lookup, not the CL definition ---
  945. ;--- However, that's what the compiler uses.  So how am I confused? ---
  946. (DEFUN (:PROPERTY RETURN MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  947.   (MAPFORMS-CALL NIL 'RETURN-FROM 'RETURN-FROM)
  948.   (SETQ USAGE (LOOP FOR (NAME . USAGE) IN *MAPFORMS-BLOCK-ALIST*
  949.             WHEN (NEQ NAME T) RETURN USAGE
  950.             FINALLY (RETURN 'EVAL)))
  951.   (MAPFORMS-LIST ORIGINAL-FORM FORM (CDR FORM) USAGE USAGE))
  952.  
  953. (DEFUN (:PROPERTY RETURN-FROM MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  954.   (MAPFORMS-RPLACA ORIGINAL-FORM FORM (CDR FORM)
  955.            (MAPFORMS-CALL (CADR FORM) 'RETURN-FROM 'RETURN-FROM))
  956.   (SETQ USAGE (OR (CDR (ASSOC (CADR FORM) *MAPFORMS-BLOCK-ALIST*)) 'EVAL))
  957.   (MAPFORMS-LIST ORIGINAL-FORM FORM (CDDR FORM) USAGE USAGE))
  958.  
  959. (DEFUN (:PROPERTY COMPILER:RETURN-FROM-T MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  960.   (MAPFORMS-CALL T 'RETURN-FROM 'RETURN-FROM)
  961.   (SETQ USAGE (OR (CDR (ASSOC T *MAPFORMS-BLOCK-ALIST*)) 'EVAL))
  962.   (MAPFORMS-LIST ORIGINAL-FORM FORM (CDDR FORM) USAGE USAGE))
  963.  
  964. ;The 8 forms/styles of DO must be procedural because it's too hard to
  965. ;get the bindings to happen at the right time in a template
  966. ;--- Here we include the oldstyle DO from Zetalisp.  What the hell.
  967. (DEFUN (:PROPERTY DO MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  968.   (MAPFORMS-DO ORIGINAL-FORM FORM NIL (CDR FORM) USAGE T))
  969.  
  970. (DEFUN (:PROPERTY DO* MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  971.   (MAPFORMS-DO ORIGINAL-FORM FORM NIL (CDR FORM) USAGE NIL))
  972.  
  973. #+LISPM
  974. (DEFUN (:PROPERTY ZL:DO-NAMED MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  975.   (MAPFORMS-DO ORIGINAL-FORM FORM (CADR FORM) (CDDR FORM) USAGE T))
  976.  
  977. #+LISPM
  978. (DEFUN (:PROPERTY ZL:DO*-NAMED MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  979.   (MAPFORMS-DO ORIGINAL-FORM FORM (CADR FORM) (CDDR FORM) USAGE NIL))
  980.  
  981. ;Doesn't allow for GO/RETURN in the step forms, which the Common Lisp manual says
  982. ;is illegal although the example expansion into TAGBODY it gives would allow it.
  983. ;This routine puts the block and tag environments around just the body forms.
  984. (DEFUN MAPFORMS-DO (ORIGINAL-FORM CURRENT-FORM BLOCK-NAME TAIL1 USAGE PARALLEL-BINDING-P)
  985.   (LET ((*MAPFORMS-BOUND-VARIABLES* *MAPFORMS-BOUND-VARIABLES*)
  986.     (*MAPFORMS-PARALLEL-BINDS* NIL)
  987.     (LOCAL-DECLARATIONS LOCAL-DECLARATIONS)
  988.     (TAIL TAIL1))
  989.     (IF (LISTP (CAR TAIL))
  990.     ;; New-style DO
  991.     (LET* ((BINDS (POP TAIL))
  992.            (ORIGINAL-BINDS BINDS)
  993.            (ENDCLAUSE (POP TAIL)))
  994.       ;; Process local declarations
  995.       (MULTIPLE-VALUE-SETQ (CURRENT-FORM TAIL LOCAL-DECLARATIONS)
  996.         (MAPFORMS-DECLARE ORIGINAL-FORM CURRENT-FORM TAIL))
  997.       ;; Process bindings of variables to initial values
  998.       (LOOP FOR BINDL ON BINDS DO
  999.         (MAPFORMS-RPLACA ORIGINAL-BINDS BINDS BINDL
  1000.              (MAPFORMS-BIND (CAR BINDL) PARALLEL-BINDING-P 'IGNORE ORIGINAL-FORM)))
  1001.       ;; Install parallel bindings
  1002.       (SETQ *MAPFORMS-BOUND-VARIABLES*
  1003.         (NCONC *MAPFORMS-PARALLEL-BINDS* *MAPFORMS-BOUND-VARIABLES*))
  1004.       (SETQ *MAPFORMS-PARALLEL-BINDS* NIL)
  1005.       ;; Begin iterated section of code, if not a do-once
  1006.       ;; All of this code except for the endtest is only conditionally executed
  1007.       (AND ENDCLAUSE *MAPFORMS-ITERATION-HOOK*
  1008.            (FUNCALL *MAPFORMS-ITERATION-HOOK* T))
  1009.       ;; Process the body
  1010.       (LET ((*MAPFORMS-TEMPLATE-FORM* CURRENT-FORM)
  1011.         (*MAPFORMS-TEMPLATE-USAGE* USAGE))
  1012.         (MAPFORMS-RPLACD ORIGINAL-FORM CURRENT-FORM
  1013.                  (LOOP FOR RDC ON CURRENT-FORM
  1014.                    WHEN (EQ (CDR RDC) TAIL) RETURN RDC)
  1015.                  (MAPFORMS-BLOCK BLOCK-NAME TAIL 'PROG)))
  1016.       ;; Go back and process step forms
  1017.       (LOOP FOR BINDL ON BINDS DO
  1018.         (OR (ATOM (CAR BINDL))
  1019.         (NULL (CDDAR BINDL))
  1020.         (LET ((BIND (CAR BINDL)))
  1021.           (MAPFORMS-RPLACA BIND BIND (CDDR BIND) (COPYFORMS-1 (CADDR BIND) 'EVAL))
  1022.           (MAPFORMS-RPLACA ORIGINAL-BINDS BINDS BINDL BIND))))
  1023.       (MAPFORMS-RPLACA ORIGINAL-FORM CURRENT-FORM TAIL1 BINDS)
  1024.       ;; Process the end-test and return values, if not a do-once
  1025.       (WHEN ENDCLAUSE
  1026.         (MAPFORMS-RPLACA ENDCLAUSE ENDCLAUSE
  1027.                  ENDCLAUSE (COPYFORMS-1 (CAR ENDCLAUSE) 'TEST))
  1028.         ;; End iterated section of code
  1029.         (AND *MAPFORMS-ITERATION-HOOK*
  1030.          (FUNCALL *MAPFORMS-ITERATION-HOOK* NIL))
  1031.         (MAPFORMS-RPLACA ORIGINAL-FORM CURRENT-FORM (CDR TAIL1)
  1032.           (MAPFORMS-LIST (CADR TAIL1) ENDCLAUSE (CDR ENDCLAUSE) 'EFFECT USAGE))))
  1033.     ;; Old-style DO
  1034.     (LET ((VAR (POP TAIL))
  1035.           (INIT (POP TAIL))
  1036.           (STEP (POP TAIL))
  1037.           (TEST (POP TAIL)))
  1038.       ;; Process local declarations
  1039.       (MULTIPLE-VALUE-SETQ (CURRENT-FORM TAIL LOCAL-DECLARATIONS)
  1040.         (MAPFORMS-DECLARE ORIGINAL-FORM CURRENT-FORM TAIL))
  1041.       ;; Process initial value form
  1042.       (MAPFORMS-RPLACA ORIGINAL-FORM CURRENT-FORM (CDR TAIL1) (COPYFORMS-1 INIT 'EVAL))
  1043.       ;; Bind the variable
  1044.       (MAPFORMS-BIND VAR NIL NIL ORIGINAL-FORM)
  1045.       ;; Begin iterated section of code
  1046.       ;; All of this code except for the endtest is only conditionally executed
  1047.       (AND *MAPFORMS-ITERATION-HOOK*
  1048.            (FUNCALL *MAPFORMS-ITERATION-HOOK* T))
  1049.       ;; Process the body
  1050.       (LET ((*MAPFORMS-TEMPLATE-FORM* CURRENT-FORM)
  1051.         (*MAPFORMS-TEMPLATE-USAGE* USAGE))
  1052.         (MAPFORMS-RPLACD ORIGINAL-FORM CURRENT-FORM
  1053.                  (LOOP FOR RDC ON CURRENT-FORM
  1054.                    WHEN (EQ (CDR RDC) TAIL) RETURN RDC)
  1055.                  (MAPFORMS-BLOCK BLOCK-NAME TAIL 'PROG)))
  1056.       ;; Process step form
  1057.       (MAPFORMS-RPLACA ORIGINAL-FORM CURRENT-FORM (CDDR TAIL1) (COPYFORMS-1 STEP 'EVAL))
  1058.       ;; Process endtest form
  1059.       (MAPFORMS-RPLACA ORIGINAL-FORM CURRENT-FORM
  1060.                (CDDDR TAIL1) (COPYFORMS-1 TEST 'TEST))
  1061.       ;; End iterated section of code
  1062.       (AND *MAPFORMS-ITERATION-HOOK*
  1063.            (FUNCALL *MAPFORMS-ITERATION-HOOK* NIL))))
  1064.     CURRENT-FORM))
  1065.  
  1066. #+LISPM        ;--- I don't know what non-LISPM implementations want for this
  1067. ;Procedural because of DEFUN-COMPATIBILITY and MAPFORMS-LAMBDA
  1068. ;This is on ZL:DEFUN because CL:DEFUN is a macro
  1069. (DEFUN (:PROPERTY ZL:DEFUN MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  1070.   (LET ((NEW-FORM (SYS:DEFUN-COMPATIBILITY (CDR FORM))))
  1071.     (IF (EQ (CDR NEW-FORM) (CDR FORM))
  1072.     (MAPFORMS-LAMBDA ORIGINAL-FORM FORM (CDDR FORM) USAGE)
  1073.     (COPYFORMS-1 NEW-FORM USAGE))))
  1074.  
  1075. ;Procedural because of MAPFORMS-LAMBDA
  1076. (DEFUN (:PROPERTY MACRO MAPFORMS) (ORIGINAL-FORM FORM USAGE)
  1077.   (MAPFORMS-LAMBDA ORIGINAL-FORM FORM (CDDR FORM) USAGE))
  1078.  
  1079. ;The template is ((REPEAT (ORDER (2 SET) (1 EVAL)))), which is too hard to
  1080. ;implement nonprocedurally because of the ORDER inside the REPEAT
  1081. (DEFUN (:PROPERTY SETQ MAPFORMS) (ORIGINAL-FORM FORM IGNORE)
  1082.   (LOOP WITH TAIL = (CDR FORM) WHILE TAIL
  1083.     AS NEW-VAL = (COPYFORMS-1 (CADR TAIL) 'EVAL)
  1084.     AS NEW-VAR = (MAPFORMS-CALL (CAR TAIL) 'SET 'SET)
  1085.     DO (MAPFORMS-RPLACA ORIGINAL-FORM FORM TAIL NEW-VAR)
  1086.        (SETQ TAIL (CDR TAIL))
  1087.        (MAPFORMS-RPLACA ORIGINAL-FORM FORM TAIL NEW-VAL)
  1088.        (SETQ TAIL (CDR TAIL)))
  1089.   FORM)
  1090.  
  1091. #+EXPLORER
  1092. (DEFUN COMPILER-LET-INTERNAL (BINDLIST BODY PROCESSING-FUNCTION &REST ADDITIONAL-ARGS)
  1093.   (PROGV (MAPCAR #'(LAMBDA (X) (IF (ATOM X) X (CAR X))) BINDLIST)
  1094.      (MAPCAR #'(LAMBDA (X) (IF (ATOM X) NIL (EVAL (CADR X)))) BINDLIST)
  1095.     (APPLY PROCESSING-FUNCTION
  1096.        (IF (CDR BODY)
  1097.            `(PROGN . ,BODY)
  1098.            (CAR BODY))
  1099.        ADDITIONAL-ARGS)))